# -*- coding: utf-8 -*-
"""
Created on Thu Feb  8 14:10:18 2018
Python内建的filter()函数用于过滤序列。

filter()也接收一个函数和一个序列。
filter()把传入的函数依次作用于每个元素，然后根据返回值是True还是False决定保留还是丢弃该元素

@author: Administrator
"""
from functools import reduce


'''
# 求素数
计算素数的一个方法是埃氏筛法，它的算法理解起来非常简单：

首先，列出从2开始的所有自然数，构造一个序列：
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...

取序列的第一个数2，它一定是素数，然后用2把序列的2的倍数筛掉：
3, 5, 7, 9, 11,13, 15, 17, 19, 21, 23, 25 ...

取新序列的第一个数3，它一定是素数，然后用3把序列的3的倍数筛掉：
5, 7, 11,13, 17, 19, 23, 25, 29 ...

取新序列的第一个数5，然后用5把序列的5的倍数筛掉：
7, 11,13, 17, 19, 23, 29 ...

不断筛下去，就可以得到所有的素数。
'''
def primes(n):
    t = list(range(2,n+1))
    
    while len(t)>0 and t[0] <= n:
        yield t[0]
        f = filter(lambda i: i%t[0] !=0, t)
        t = list(f)


def primes2():
    # 定义一个生成器generator,它是一个无限序列, 从2开始的自然数
    def get_data():
        n = 2
        while True:
            yield n
            n = n+1


    # 定义一个筛选函数
    def not_divisible(n):
        return lambda x: x % n > 0
    
    
    it = get_data()  # 初始序列,替代直接用list构造，大大节约内存
    while True:
        n = next(it)  # 返回序列的第一值
        yield n
        # it = filter(lambda x: x % n > 0, it)  # 使用lambda表达式结果不对，n不认识
        # it = filter(lambda x,m=n: x % m > 0, it) # 需要这样子写才可以
        it = filter(not_divisible(n), it)  # 构造新序列
        

'''
回数是指从左向右读和从右向左读都是一样的数，例如12321，909。请利用filter()筛选出回数：
'''
def is_palindrome(n):
    # 定义一个生成器generator,它是一个无限序列, 从1开始的自然数
    def get_data():
        n=1
        while True:
            yield n
            n=n+1
    
    
    # 定义筛选器
    def rule():
        pass
        
    


def main():
    t = list(range(10))
    # map
    m = map(lambda x: x+1, t)
    # reduce
    r = reduce(lambda x, y: x+y, t)
    '''
    # filer
    用filter()这个高阶函数，关键在于正确实现一个“筛选”函数
    注意到filter()函数返回的是一个Iterator，也就是一个惰性序列，
    所以要强迫filter()完成计算结果，需要用list()函数获得所有结果并返回list
    '''
    f = filter(lambda x: x%2 == 0, t)
    
    print('list:\t', t)
    print('map:\t',list(m))
    print('reduce:\t', r)
    print('filter:\t', list(f))
    
    print('prime [1-20]:')
    
#    p = primes(10)
#    for i in p:
#        print(i)
        
#    g = primes2()
#    n = next(g)
#    while n < 20:
#        print(n)
#        n = next(g)
            
    for i in primes2():
        if i < 20:
            print(i)
        else:
            break
        

if __name__ == '__main__':
    main()
    
